using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using GeneticAlgorithms;
using WeifenLuo.WinFormsUI.Docking;

namespace GADemo
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            LoadDocks();
            //CreateListener();
            //RunGA();
        }

        private void CreateListener()
        {
            //TextWriterTraceListener listener = new TextWriterTraceListener(
        }

        private void LoadDocks()
        {
            propsForm = new PropertiesForm();
            graphForm = new GraphForm();
            statsForm = new StatsForm();
            traceForm = new TraceForm();

            statsForm.Show(dockPanel1, DockState.DockLeft);
            propsForm.Show(dockPanel1, DockState.DockRight);
            traceForm.Show(dockPanel1, DockState.DockBottomAutoHide);
            graphForm.Show(dockPanel1, DockState.Document);
        }

        PropertiesForm propsForm;
        GraphForm graphForm;
        StatsForm statsForm;
        TraceForm traceForm;
        NewPopulationForm newPopForm;

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            graphForm.ResetGraph();
            CreateGA();
            UpdateControls();
        }

        private void UpdateControls()
        {
            propsForm.SetGA(ga);
            statsForm.SetStatus(ga);
            graphForm.UpdateGraph(ga);
        }

        private void CreateGA()
        {
            if (newPopForm == null)
                newPopForm = new NewPopulationForm();

            if (newPopForm.ShowDialog() == DialogResult.OK)
            {
                ga = newPopForm.GeneticAlgorithm;
                ga.Stepped += new CancelEventHandler(ga_Stepped);

                graphForm.ResetGraph();
                graphForm.UpdateGraph(ga);
                propsForm.SetGA(ga);

                actInitGA.Enabled = true;
                actRunGA.Enabled = true;
                actStepGA.Enabled = true;
            }

            /*
            IAlphabet<char> charAlphabet = new LettersAlphabet(LetterCases.Uppercase);
            ArrayGenome<char> baseGenome = new ArrayGenome<char>(charAlphabet,
                "HelloWorld".length);

            IGenomeFactory<IGenome<char>> factory =
                new CloneableGenomeFactory<IGenome<char>>(
                baseGenome);

            IFitnessProvider<char> fitnessProvider = new HelloWorldFitnessProvider();
            IGeneticInitializer<char> initializer = new SimpleInitializer<char>();
            IGeneticSelector<char> selector = new RouletteSelector<char>();
            IGeneticMater<char> mater = new SimpleMater<char>();
            IGeneticCrossover<char> crossover = new SinglePointCrossover<char>();
            IGeneticMutator<char> mutator = new FlipMutator<char>(initializer);
            mutator.MutationProbability = .1;

            FixedSizePopulation<char> pop = new FixedSizePopulation<char>(40,
                factory, fitnessProvider, initializer, selector, mater,
                crossover, mutator);
            pop.EliteSize = 1;

            GAConfigurationBase config = new GAConfigurationBase();
            config.MaxGenerations = 1000;
            config.DesiredFitness = 100;

            ga = new GeneticAlgorithm<char>(pop, config);
             */
        }

        IGeneticAlgorithm ga;

        private void RunGA()
        {
            if (ga != null)
            {
                bgwEvolver.RunWorkerAsync();
                actPauseGA.Enabled = true;
                actNewGA.Enabled = false;
                actInitGA.Enabled = false;
                actStepGA.Enabled = false;
                actRunGA.Enabled = false;
            }
        }

        private void ga_Stepped(object sender, CancelEventArgs e)
        {
            int sleepTime = Properties.Settings.Default.StepSleepTime;
            if (sleepTime > 0)
            {
                Thread.Sleep(sleepTime);
            }

            bgwEvolver.ReportProgress(0);
            if (bgwEvolver.CancellationPending)
                e.Cancel = true;
        }

        private void bgwEvolver_DoWork(object sender, DoWorkEventArgs e)
        {
            ga.Evolve();   
        }

        private void bgwEvolver_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            tslStatus.Text = ga.Status.RunStatus.ToString();
            statsForm.SetStatus(ga);
            graphForm.UpdateGraph(ga);
        }

        private void bgwEvolver_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string statusLabel;
            if (e.Cancelled == false)
            {
                statusLabel = "Completed";
            }
            else
            {
                actStepGA.Enabled = true;
                actRunGA.Enabled = true;
                statusLabel = "Paused";
            }
            MessageBox.Show(String.Format("Evolution {0}.",
                statusLabel.ToLower()));
            tslStatus.Text = statusLabel;

            actNewGA.Enabled = true;
            actInitGA.Enabled = true;
            actPauseGA.Enabled = false;
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (bgwEvolver.IsBusy)
                bgwEvolver.CancelAsync();

            Properties.Settings.Default.Save();
        }

        private void ResetGA()
        {
            if (ga != null)
            {
                ga.Initialize();
                statsForm.SetStatus(ga);
                graphForm.ResetGraph();
                graphForm.UpdateGraph(ga);
                actRunGA.Enabled = true;
                actStepGA.Enabled = true;
            }
        }

        private void PauseGA()
        {
            if (bgwEvolver.IsBusy)
            {
                bgwEvolver.CancelAsync();
            }
        }


        private void StepGA()
        {
            if ((ga != null) && (ga.Status.RunStatus != GARunStatus.Running))
                ga.DoStep();
        }

        private void actNewGA_Execute(object sender, EventArgs e)
        {
            CreateGA();
        }

        private void actInitGA_Execute(object sender, EventArgs e)
        {
            ResetGA();
        }

        private void actRunGA_Execute(object sender, EventArgs e)
        {
            RunGA();
        }

        private void actPauseGA_Execute(object sender, EventArgs e)
        {
            PauseGA();
        }

        private void actStepGA_Execute(object sender, EventArgs e)
        {
            StepGA();
        }
    }
}